iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
Build on Google AI

從 Vibe Coding 到 Production:用 Google AI 打造上線守門員系列 第 5

Day 5|刻意寫壞它:加入越權、個資暴露與不安全的 API

  • 分享至 

  • xImage
  •  

昨天,我們完成了 Vibe Guard 的安全基線。使用者可以登入並建立專案,Firestore Security Rules 也會限制使用者只能存取自己的資料。

今天要反過來做:刻意加入三個常見問題,建立 Production Readiness Agent 的第一組測試答案。

請勿部署:今天的程式碼故意不安全,只能使用假帳號與假資料,在 Firebase Local Emulator Suite 中操作。程式也會拒絕在非 localhost 網域執行。

今天要加入哪些問題?

https://ithelp.ithome.com.tw/upload/images/20260824/20121335n4tBXKjMpK.png

三個問題不是彼此獨立。過度寬鬆的授權讓攻擊者取得別人的文件,文件又包含不必要的 Email,而不安全的畫面輸出會把惡意內容交給瀏覽器解析。Production 事故經常就是多個小錯誤串在一起。

問題一:登入不等於有權限

Day 4 的規則會比較文件中的 ownerId 與登入者 UID。今天把規則改成:

match /projects/{projectId} {
  allow read, write: if request.auth != null;
}

這條規則只回答「使用者有沒有登入」,沒有回答「使用者能不能操作這筆專案」。因此任何登入者都能讀寫 projects Collection 中的所有文件。

前端查詢也從只讀取自己的專案:

query(
  collection(db, "projects"),
  where("ownerId", "==", user.uid)
)

改成讀取全部專案:

query(collection(db, "projects"))

前端的 where 不是授權控制。即使畫面仍只查詢自己的資料,使用者也能修改瀏覽器程式或直接呼叫 Firestore API。真正的防線必須位於 Security Rules。

問題二:把 Email 放進每一筆文件

新增專案時,我們故意把登入者 Email 一起寫入:

await addDoc(collection(db, "projects"), {
  name,
  launchGoal,
  ownerId: auth.currentUser.uid,
  ownerEmail: auth.currentUser.email,
  createdAt: serverTimestamp()
});

Vibe Guard 顯示專案清單不需要 Email。只保存 ownerId 已足以判斷擁有者。多存一份 Email 會增加資料外洩範圍,也可能在使用者變更 Email 後留下過期資料。

「資料庫中有 Email」本身不一定是漏洞。真正的問題是:這個欄位對功能沒有必要,而且寬鬆的授權規則讓其他登入者可以讀取它。

問題三:用 innerHTML 顯示不可信輸入

安全基線使用 textContent,瀏覽器只會把專案名稱當成文字。今天改用字串組合與 innerHTML

item.innerHTML = `
  <strong>${project.name}</strong>
  <p>${project.launchGoal}</p>
  <small>Owner: ${project.ownerEmail}</small>
`;

現在專案名稱與上線目標會被當成 HTML 解析。即使輸入欄位限制長度,也沒有改變資料是不可信輸入的事實。

為了安全示範,我們只使用不執行 JavaScript 的標記:
<mark>這不是純文字</mark>
如果儲存後文字出現黃色標記,就證明瀏覽器把輸入當成 HTML,而不是普通文字。請不要輸入會執行程式碼或載入外部資源的內容。

實際重現三個問題

步驟一:建置並啟動 Emulator

cd /media/mickey/777/ithome/demo-app
npm run build
npm run emulators

開啟 http://127.0.0.1:5000。頁面上方會顯示紅色警告,提醒這是刻意不安全的版本。

步驟二:使用第一個帳號建立專案
1. 建立 user1@example.test
1. 新增專案,名稱輸入 User 1 Project。
1. 確認畫面顯示標記效果與 Owner Email。
1. 登出

步驟三:使用第二個帳號讀取資料

  1. 建立 user2@example.test
  2. 登入後查看「所有專案」。
  3. 確認畫面仍顯示 User 1 建立的專案。
  4. 確認畫面同時顯示 user1@example.test
    第二個帳號不需要知道文件 ID,也不需要管理員權限。只要成功登入,就能透過 Firestore API 查詢其他人的資料。這就是完整的越權路徑。

把結果寫成 Ground Truth

未來 Gemini 不能只回答「Security Rules 不安全」。一項合格 Finding 至少要包含位置、前提、操作與影響。
https://ithelp.ithome.com.tw/upload/images/20260824/201213350iGRCpmXp3.png

嚴重度不能只看程式碼長相。AUTH-01 讓任意登入者跨帳號取資料,是已經可以重現的授權問題。PRIV-01 的影響來自不必要的資料欄位與越權讀取組合。INPUT-01 已證明存在 HTML Injection,但是否能形成可利用的 XSS,還要根據瀏覽器行為與輸入情境進一步驗證。

為什麼不急著修正?

這些問題會保留在 Demo 中,作為後續 Agent 的固定考題。Day 7 與 Day 8 會分別深入授權和個資外洩,再比較修正前後的差異。

明天,我們會第一次把這個專案交給 Gemini。我們將在 Google AI Studio 設計 Code Reviewer Prompt,觀察模型能抓到哪些問題,又會產生哪些沒有證據的警告。

參考資料

Firebase, Writing conditions for Cloud Firestore Security Rules
OWASP, A01:2021 Broken Access Control
MDN, Element: innerHTML property


上一篇
Day 4|動手建立 Demo:用 Firebase 完成登入、資料庫與部署基礎
下一篇
Day 6|第一次交給 Gemini:用 Google AI Studio 建立程式碼 Reviewer
系列文
從 Vibe Coding 到 Production:用 Google AI 打造上線守門員10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言